package cn.itsource.blog.service.impl;

import cn.itsource.blog.mapper.ArticleTypeMapper;
import cn.itsource.blog.service.IArticleTypeService;
import cn.itsource.blog.domain.ArticleType;
import cn.itsource.blog.query.ArticleTypeQuery;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
// Transactional：用来控制事务的注解；readOnly：只读；propagation：事务传播机制
//  Propagation.SUPPORTS：支持当前事务，如果没有当前事务，就以非事务方法执行
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
@CacheConfig(cacheNames="articleType") // CacheConfig：共享的一些常见缓存设置  类上加注解，可以全局使用（下面就可以不用写cacheNames，但是key不能在类上加）
public class ArticleTypeServiceImpl implements IArticleTypeService {

    @Autowired
    private ArticleTypeMapper articleTypeMapper;

    @Transactional
    @Override
    // @CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作
    // 一般都用在增删改上面，每次进行操作都需要清除一次缓存
    @CacheEvict(key = "'typeTree'")
    public void add(ArticleType articleType) {
        articleTypeMapper.add(articleType);
    }

    @Transactional
    @Override
    @CacheEvict(key = "'typeTree'")
    public void update(ArticleType articleType) {
        // 设置更新时间为当前系统时间
        articleType.setUpdateTime(new Date());
        articleTypeMapper.update(articleType);
    }

    @Transactional
    @Override
    @CacheEvict(key = "'typeTree'")
    public void delete(Long id) {
        articleTypeMapper.delete(id);
    }

    @Override
    public ArticleType getOne(Long id) {
        return articleTypeMapper.getOne(id);
    }

    @Override
    public List<ArticleType> getAll() {
        return articleTypeMapper.getAll();
    }

    @Transactional
    @Override
    @CacheEvict(key = "'typeTree'")
    public void patchDelete(Long[] ids) {
        articleTypeMapper.patchDelete(ids);
    }

    @Override
    public PageInfo<ArticleType> pageQuery(ArticleTypeQuery query) {
        //原生的写法：1.先查询总页数  2.再根据分页的信息查询当前页的数据
        //PageHelper的写法：开启分页
//                PageHelper.startPage(当前页,每页显示的条数);
        PageHelper.startPage(query.getCurrentPage(), query.getPageSize());
        //分页查询：只要开启了分页，它会帮助我们做什么事情？
        //1.先查询总数量  //2.根据application.yml中驱动名自动实现分页，如果是mysql就用limit
        //3.自动计算limit的第一个值：limit a,b [a = 当前页的起始下标 = (当前页-1)*每页显示的条数]
//        List<Emp> emps = empMapper.pageQuery(empQuery);
        List<ArticleType> list = articleTypeMapper.pageQuery(query);
        return new PageInfo(list);
    }

    @Override
    //  Cacheable：表示该方法会开启缓存， 每次调用类型树方法都先清除一次缓存，更节约内存空间
    @Cacheable(cacheNames="articleType" ,key = "'typeTree'")
    public List<ArticleType> getTypeTree() {
           return getTypeTreeFromDB();
    }

    public List<ArticleType> getTypeTreeFromDB(){
        // 存储类型树的集合
        List<ArticleType> typeTree = new ArrayList<>();
        // 调用 articleTypeMapper.getAll()方法获取所有的数据
        List<ArticleType> articleTypes = articleTypeMapper.getAll();
        // map集合用来存储ArticleType数据，key是ID
        Map<Long, ArticleType> typeMap = new HashMap<>();

        // 遍历所有的articleTypes并将他们装到map集合中
        for (ArticleType articleType : articleTypes) {
            typeMap.put(articleType.getId(),articleType);
        }

        for (ArticleType type : articleTypes) {
            // 如果getParentId为空说明没有父类，他就是父类，直接将他装到类型树里
            if (type.getParentId() == null) {
                typeTree.add(type);
            }else {
                // 如果getParentId不为空说明有父类，通过父类id获取整个父类articleType对象
                Long parentId = type.getParentId();
                ArticleType articleType = typeMap.get(parentId);
                // 如果父类articleType对象不为空，就把和这个对象装到父类articleType对象的children属性集合里，形成类型树
                if (articleType!= null) {
                    articleType.getChildren().add(type);
                }
            }
        }
        return typeTree;
    }
}
